package org.example.gxpt.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.example.gxpt.common.constant.*;
import org.example.gxpt.common.context.LoginContext;
import org.example.gxpt.common.context.SecurityContext;
import org.example.gxpt.common.properties.JwtProperties;
import org.example.gxpt.common.properties.RedisProperties;
import org.example.gxpt.common.result.PageResult;
import org.example.gxpt.common.utils.JwtUtil;
import org.example.gxpt.mapper.InstrumentAdminMapper;
import org.example.gxpt.mapper.ShowroomMapper;
import org.example.gxpt.mapper.UserRoleMapper;
import org.example.gxpt.pojo.dto.InstrumentAdminDTO;
import org.example.gxpt.pojo.dto.InstrumentAdminPageQueryDTO;
import org.example.gxpt.pojo.dto.InstrumentAdminUpdateDTO;
import org.example.gxpt.pojo.dto.LoginDTO;
import org.example.gxpt.pojo.entity.InstrumentAdmin;
import org.example.gxpt.pojo.entity.Showroom;
import org.example.gxpt.pojo.entity.UserRole;
import org.example.gxpt.pojo.userdetails.LoginUser;
import org.example.gxpt.pojo.vo.InstrumentAdminLoginVO;
import org.example.gxpt.pojo.vo.InstrumentAdminQueryVO;
import org.example.gxpt.service.InstrumentAdminService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class InstrumentAdminServiceImpl implements InstrumentAdminService {

    @Autowired
    private InstrumentAdminMapper instrumentAdminMapper;

    @Autowired
    private ShowroomMapper showroomMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private UserRoleMapper userRoleMapper;

    /**
     * 注册设备管理员
     *
     * @param instrumentAdminDTO
     */
    @Override
    @Transactional
    public void save(InstrumentAdminDTO instrumentAdminDTO) {

        InstrumentAdmin instrumentAdmin = new InstrumentAdmin();
        BeanUtils.copyProperties(instrumentAdminDTO, instrumentAdmin);
        Showroom showroom = showroomMapper.getShowroomById(instrumentAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");
//        instrumentAdmin.setPassword(DigestUtils.md5DigestAsHex(instrumentAdmin.getPassword().getBytes()));
        instrumentAdmin.setPassword(passwordEncoder.encode(instrumentAdminDTO.getPassword()));
        instrumentAdminMapper.insert(instrumentAdmin);
        UserRole userRole = new UserRole();
        userRole.setUsername(instrumentAdmin.getUsername());
        userRole.setPhone(instrumentAdmin.getPhone());
        userRole.setRole(RoleConstant.INSTRUMENT_ADMIN);
        userRole.setRoleId(instrumentAdmin.getId());
        userRoleMapper.insert(userRole);

    }

    /**
     * 设备管理员登陆
     *
     * @param loginDTO
     * @return
     */
    @Override
    public InstrumentAdminLoginVO login(LoginDTO loginDTO) {
        //存储当前登录用户的角色信息，在UserDetailsServiceImpl中取出用于判断当前登录用户的角色，从对应的mapper中查询
        LoginContext.setCurrentRole(LoginRoleConstant.INSTRUMENT_ADMIN);

        //AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        //如果认证没通过，给出对应提示
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("登录失败");
        }

        //如果认证通过，使用生成一个jwt，存入loginVO中返回
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        InstrumentAdmin instrumentAdmin = loginUser.getInstrumentAdmin();

        //生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.ROLE, RoleConstant.INSTRUMENT_ADMIN);
        claims.put(JwtClaimsConstant.ID, instrumentAdmin.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getSecretKey(),
                jwtProperties.getTtl(),
                claims);

        Showroom showroom = showroomMapper.getShowroomById(instrumentAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

        InstrumentAdminLoginVO instrumentAdminLoginVO = InstrumentAdminLoginVO.builder()
                .id(instrumentAdmin.getId())
                .name(instrumentAdmin.getName())
                .username(instrumentAdmin.getUsername())
                .token(token)
                .avatar(instrumentAdmin.getAvatar())
                .showroomId(instrumentAdmin.getShowroomId())
                .showroomName(showroom.getName())
                .build();

        //把完整的用户信息存入redis key:userid value:User对象
        redisTemplate.opsForValue().set(RedisConstant.LOGIN_INSTRUMENT_ADMIN + instrumentAdmin.getId().toString(), loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);
//        redisTemplate.opsForValue().set(RedisConstant.LOGIN_USER + token, loginUser, redisProperties.getTtl(), TimeUnit.MILLISECONDS);

        return instrumentAdminLoginVO;
    }

    /**
     * 根据id更新设备管理员
     *
     * @param instrumentAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateById(InstrumentAdminUpdateDTO instrumentAdminUpdateDTO) {

        InstrumentAdmin instrumentAdmin = new InstrumentAdmin();
        BeanUtils.copyProperties(instrumentAdminUpdateDTO, instrumentAdmin);

        Showroom showroom = showroomMapper.getShowroomById(instrumentAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");
        //instrumentAdmin.setPassword(DigestUtils.md5DigestAsHex(instrumentAdminDTO.getPassword().getBytes()));
        instrumentAdmin.setPassword(passwordEncoder.encode(instrumentAdminUpdateDTO.getPassword()));
        instrumentAdminMapper.update(instrumentAdmin);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_INSTRUMENT_ADMIN + instrumentAdmin.getId().toString());
        UserRole userRole = UserRole.builder()
                .role(RoleConstant.INSTRUMENT_ADMIN)
                .roleId(instrumentAdmin.getId())
                .phone(instrumentAdmin.getPhone())
                .username(instrumentAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);
    }

    /**
     * 查询所有设备管理员
     *
     * @return
     */
    @Override
    public List<InstrumentAdminQueryVO> listAll() {
        return instrumentAdminMapper.listAll();
    }

    /**
     * 分页查询设备管理员
     *
     * @param instrumentAdminPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuery(InstrumentAdminPageQueryDTO instrumentAdminPageQueryDTO) {

        PageHelper.startPage(instrumentAdminPageQueryDTO.getPage(), instrumentAdminPageQueryDTO.getPageSize());

        Page<InstrumentAdminQueryVO> page = instrumentAdminMapper.pageQuery(instrumentAdminPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());

    }

    /**
     * 根据id查询设备管理员
     *
     * @param id
     * @return
     */
    @Override
    public InstrumentAdmin getInstrumentAdminById(Integer id) {
        return instrumentAdminMapper.selectById(id);
    }

    /**
     * 根据id删除设备管理员
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        instrumentAdminMapper.deleteById(id);
        userRoleMapper.delete(UserRole.builder().roleId(id).role(RoleConstant.INSTRUMENT_ADMIN).build());
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_INSTRUMENT_ADMIN + id.toString());
    }

    /**
     * 根据上下文更新设备管理员
     *
     * @param instrumentAdminUpdateDTO
     */
    @Override
    @Transactional
    public void updateByContext(InstrumentAdminUpdateDTO instrumentAdminUpdateDTO) {

        Long id = null;
        try {
            id = SecurityContext.getCurrentLoginUser().getInstrumentAdmin().getId();
        } catch (Exception e) {
            throw new RuntimeException("用户未登录");
        }

        InstrumentAdmin instrumentAdmin = new InstrumentAdmin();
        BeanUtils.copyProperties(instrumentAdminUpdateDTO, instrumentAdmin);
        instrumentAdmin.setId(id);

        Showroom showroom = showroomMapper.getShowroomById(instrumentAdmin.getShowroomId());
        if (Objects.isNull(showroom)) throw new RuntimeException("展厅不存在");

//      showroomAdmin.setPassword(DigestUtils.md5DigestAsHex(showroomAdminDTO.getPassword().getBytes()));
        instrumentAdmin.setPassword(passwordEncoder.encode(instrumentAdminUpdateDTO.getPassword()));
        instrumentAdminMapper.update(instrumentAdmin);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_INSTRUMENT_ADMIN + instrumentAdmin.getId().toString());
        UserRole userRole = UserRole.builder()
                .role(RoleConstant.INSTRUMENT_ADMIN)
                .roleId(instrumentAdmin.getId())
                .phone(instrumentAdmin.getPhone())
                .username(instrumentAdmin.getUsername())
                .build();
        userRoleMapper.update(userRole);
    }

    /**
     * 更新状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateStatus(Long id, Integer status) {
        instrumentAdminMapper.updateStatus(id, status);
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_INSTRUMENT_ADMIN + id.toString());
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {
        UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Long id = loginUser.getInstrumentAdmin().getId();
        //在Redis中删除用户信息
        redisTemplate.opsForValue().getOperations().delete(RedisConstant.LOGIN_INSTRUMENT_ADMIN + id);
    }

}
